/**
 * @file liveroom.js 直播模式房间管理sdk
 * @author binniexu
 */
var webim = require('./webim_wx.js');
var webimhandler = require('./webim_handler.js');
var tls = require('./tls.js');
var encrypt = require('./encrypt.js');
var serverDomain = '',		// 后台域名
  heart = '',				// 判断心跳变量
  requestSeq = 0,			// 请求id
  requestTask = [],		// 请求task
  // 用户信息
  accountInfo = {
    userID: '',			// 用户ID
    userName: '',		// 用户昵称
    userAvatar: '',		// 用户头像URL
    userSig: '',		// IM登录凭证
    sdkAppID: '',		// IM应用ID
    accountType: '',	// 账号集成类型
    accountMode: 0,		//帐号模式，0-表示独立模式，1-表示托管模式
    token: ''			//登录RoomService后使用的票据
  },
  // 房间信息
  roomInfo = {
    roomID: '',			// 视频位房间ID
    roomInfo: '',		// 房间名称
    mixedPlayURL: '', 	// 混流地址
    isCreator: false,	// 是否为创建者
    pushers: [],		// 当前用户信息
    isLoginIM: false,	// 是否登录IM
    isJoinGroup: false,	// 是否加入群
    isDestory: false,	// 是否已解散
    hasJoinPusher: false
  },
  // 事件
  event = {
    onGetPusherList: function () {
    },		// 初始化成员列表
    onPusherJoin: function () {
    },			// 进房通知
    onPusherQuit: function () {
    },			// 退房通知
    onRoomClose: function () {
    },			// 群解散通知
    onRecvRoomTextMsg: function () {
    },		// 消息通知
    onRecvJoinPusherRequest: function () {
    }, //大主播收到小主播连麦请求通知
    onKickOut: function () {
    }, //小主播被踢通知
    onRecvRoomCustomMsg: function () {
    }, //自定义消息通知
    onSketchpadData: function () {
    },
    onPushersChange: function () {
    }		//当推流成员有变更时回调，主播、连麦观众、普通观众都能收到此通知
  };
// 请求数
var requestNum = 0;
var requestJoinCallback = null;
var bigAnchorStreamID = '';
var bigAnchorWidth = 360;
var bigAnchorHeight = 640;
var gTimeoutID = null;

/**
 * [request 封装request请求]
 * @param {options}
 *   url: 请求接口url
 *   data: 请求参数
 *   success: 成功回调
 *   fail: 失败回调
 *   complete: 完成回调
 */
function request(options) {
  if (!serverDomain) {
    console.log('请求服务器域名为空，请将wxlite/config里面的url配置成你的服务器域名');
    options.fail && options.fail({
      errCode: -9,
      errMsg: '请求服务器域名为空，请将wxlite/config里面的url配置成你的服务器域名'
    });
    return;
  }
  requestNum++;
  console.log('requestNum: ', requestNum);
  requestTask[ requestSeq++ ] = wx.request({
    url: serverDomain + options.url + (options.params ? ('?' + formatParams(options.params) + '&') : '?') + 'userID=' + accountInfo.userID + (accountInfo.token ? '&token=' + accountInfo.token : ""),
    data: options.data || {},
    method: 'POST',
    header: {
      'content-type': 'application/json' // 默认值
    },
    // dataType: 'json',
    success: options.success || function () {
    },
    fail: options.fail || function () {
    },
    complete: options.complete || function () {
      requestNum--;
      // console.log('complete requestNum: ',requestNum);
    }
  });
}

//url encode编码
function formatParams(data) {
  var arr = [];
  for (var name in data) {
    arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[ name ]));
  }
  return arr.join("&");
}

/**
 * [login 初始化登录信息]
 * @param {options}
 *   data: {
 *   	serverDomain: 请求域名
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   userName: 用户昵称
 */
function login(options) {
  if (!options || !options.data.serverDomain) {
    console.log('init参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'init参数错误'
    });
    return;
  }
  serverDomain = options.data.serverDomain;
  accountInfo.userID = options.data.userID;
  accountInfo.userSig = options.data.userSig;
  accountInfo.sdkAppID = options.data.sdkAppID;
  accountInfo.accountType = options.data.accType;
  accountInfo.roomID = options.data.roomID;
  accountInfo.userName = options.data.userName;
  accountInfo.userAvatar = options.data.userAvatar || '';
  request({
    url: 'login',
    params: {
      accountType: accountInfo.accountType,
      sdkAppID: accountInfo.sdkAppID,
      userSig: accountInfo.userSig
    },
    data: {},
    success: function (ret) {
      console.info(ret)
      if (ret.data.code) {
        console.error("登录到RoomService后台失败:", JSON.stringify(ret));
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message
        });
        return;
      }
      accountInfo.token = ret.data.token;
      accountInfo.userID = ret.data.userID;
      // 登录IM
      loginIM({
        success: function (ret) {
          options.success && options.success({
            userID: accountInfo.userID,
            userName: accountInfo.userName
          });
        },
        fail: function (ret) {
          console.error("IM登录失败:", JSON.stringify(ret));
          options.fail && options.fail({
            errCode: -999,
            errMsg: "IM登录失败"
          });
        }
      });
    },
    fail: function (ret) {
      console.error("登录到RoomService后台失败:", JSON.stringify(ret));
      options.fail && options.fail(ret);
    }
  });
}

/**
 * [logout 结束初始化信息]
 */
function logout() {
  request({
    url: "logout",
    success: function (ret) {
    },
    fail: function (ret) {
    }
  });
  serverDomain = '';
  accountInfo.userID = '';
  accountInfo.userSig = '';
  accountInfo.sdkAppID = '';
  accountInfo.accountType = '';
  accountInfo.userName = '';
  accountInfo.userAvatar = '';
  accountInfo.token = '';
  // 退出IM登录
  webimhandler.logout();
}

/**
 * [loginIM 登录IM]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function loginIM(options) {
  console.info(options)
  // 初始化设置参数
  webimhandler.init({
    accountMode: accountInfo.accountMode,
    accountType: accountInfo.accountType,
    sdkAppID: accountInfo.sdkAppID,
    avChatRoomId: accountInfo.roomID || 0,
    selType: webim.SESSION_TYPE.GROUP,
    selToID: accountInfo.roomID || 0,
    selSess: null //当前聊天会话
  });
  //当前用户身份
  var loginInfo = {
    'sdkAppID': accountInfo.sdkAppID, //用户所属应用id,必填
    'appIDAt3rd': accountInfo.sdkAppID, //用户所属应用id，必填
    'accountType': accountInfo.accountType, //用户所属应用帐号类型，必填
    'identifier': accountInfo.userID, //当前用户ID,必须是否字符串类型，选填
    'identifierNick': accountInfo.userName, //当前用户昵称，选填
    'userSig': accountInfo.userSig, //当前用户身份凭证，必须是字符串类型，选填
  };
  console.log('loginInfo:' + JSON.stringify(loginInfo))
  //监听（多终端同步）群系统消息方法，方法都定义在demo_group_notice.js文件中
  var onGroupSystemNotifys = {
    // 群被解散(全员接收)
    "5": function (notify) {
      roomInfo.isDestory = true;
      event.onRoomClose();
    },
    "11": webimhandler.onRevokeGroupNotify, //群已被回收(全员接收)
    // 用户自定义通知(默认全员接收)
    "255": function (notify) {
      // console.error('收到系统通知：', notify.UserDefinedField);
      var content = JSON.parse(notify.UserDefinedField);
      if (content && content.cmd == 'notifyPusherChange') {
        event.onPushersChange && event.onPushersChange();
        mergePushers();
      }
    }
  };
  //监听连接状态回调变化事件
  var onConnNotify = function (resp) {
    switch (resp.ErrorCode) {
    case webim.CONNECTION_STATUS.ON:
      //webim.Log.warn('连接状态正常...');
      break;
    case webim.CONNECTION_STATUS.OFF:
      webim.Log.warn('连接已断开，无法收到新消息，请检查下你的网络是否正常');
      break;
    default:
      webim.Log.error('未知连接状态,status=' + resp.ErrorCode);
      break;
    }
  };
  //监听事件
  var listeners = {
    "onConnNotify": webimhandler.onConnNotify, //选填
    "onBigGroupMsgNotify": function (msg) {
      webimhandler.onBigGroupMsgNotify(msg, function (msgs) {
        receiveMsg(msgs);
      }, function (datas) {
        //收到白板数据
        console.log("LiveRoom callback --> 收到白板数据")
        onSketchpadData(datas);
      })
      // webimhandler.onBigGroupMsgNotify(msg, function (msgs) {
      // 	receiveMsg(msgs);
      // })
    }, //监听新消息(大群)事件，必填
    "onMsgNotify": function (newMsgList) { //监听新消息(私聊(包括普通消息和全员推送消息)，普通群(非直播聊天室)消息)事件，必填
      webimhandler.onMsgNotify(newMsgList, function (msg) {
        recvC2CMsg(msg);
      });
    },
    "onGroupSystemNotifys": onGroupSystemNotifys, //监听（多终端同步）群系统消息事件，必填
    "onGroupInfoChangeNotify": webimhandler.onGroupInfoChangeNotify,
    // 'onKickedEventCall': self.onKickedEventCall // 踢人操作
  };
  //其他对象，选填
  var others = {
    'isAccessFormalEnv': true, //是否访问正式环境，默认访问正式，选填
    'isLogOn': false //是否开启控制台打印日志,默认开启，选填
  };
  if (accountInfo.accountMode == 1) { //托管模式
    webimhandler.sdkLogin(loginInfo, listeners, others, 0, afterLoginIM, options);
  } else { //独立模式
    //sdk登录
    webimhandler.sdkLogin(loginInfo, listeners, others, 0, afterLoginIM, options);
  }
}

function afterLoginIM(options) {
  if (options.errCode) {
    // webim登录失败
    console.log('webim登录失败:', options);
    options.callback.fail && options.callback.fail({
      errCode: -2,
      errMsg: 'IM登录失败，如果你是在配置线上环境，请将IM域名[https://webim.tim.qq.com]配置到小程序request合法域名'
    });
    return;
  }
  // webim登录成功
  console.log('webim登录成功');
  roomInfo.isLoginIM = true;
  options.callback.success && options.callback.success({
    userName: accountInfo.userName
  });
}

function afterJoinBigGroup(options) {
  if (options.errCode) {
    console.log('webim进群失败: ', options);
    options.callback.fail && options.callback.fail({
      errCode: -2,
      errMsg: 'IM进群失败'
    });
    return;
  }
  roomInfo.isJoinGroup = true;
  console.log('进入IM房间成功: ', roomInfo.roomID);
  options.callback.success && options.callback.success({});
}

function onSketchpadData(data) {
  event.onSketchpadData(data);
}

/**
 * [receiveMsg 接收消息处理]
 * @param {options}
 *
 * @return event.onRecvRoomTextMsg
 *   roomID: 房间ID
 *   userID: 用户ID
 *   nickName: 用户昵称
 *   headPic: 用户头像
 *   textMsg: 文本消息
 *   time: 消息时间
 */
function receiveMsg(msg) {
  if (!msg.content) {
    return;
  }
  console.log('IM消息: ', JSON.stringify(msg));
  var time = new Date();
  var h = time.getHours() + '', m = time.getMinutes() + '', s = time.getSeconds() + '';
  h.length == 1 ? (h = '0' + h) : '';
  m.length == 1 ? (m = '0' + m) : '';
  s.length == 1 ? (s = '0' + s) : '';
  time = h + ':' + m + ':' + s;
  msg.time = time;
  if (msg.fromAccountNick == '@TIM#SYSTEM') {
    msg.fromAccountNick = '';
    msg.content = msg.content.split(';');
    msg.content = msg.content[ 0 ];
    event.onRecvRoomTextMsg && event.onRecvRoomTextMsg({
      roomID: roomInfo.roomID,
      userID: msg.fromAccountNick,
      userName: msg.userName,
      userAvatar: msg.userAvatar,
      message: msg.content,
      time: msg.time
    });
  } else {
    var contentObj, newContent;
    newContent = msg.content.split('}}');
    contentObj = JSON.parse(newContent[ 0 ] + '}}');
    if (contentObj.cmd == 'CustomTextMsg') {
      msg.userName = contentObj.data.nickName;
      msg.userAvatar = contentObj.data.headPic;
      var content = '';
      for (var i = 1; i < newContent.length; i++) {
        if (i == newContent.length - 1)
          content += newContent[ i ];
        else content += newContent[ i ] + '}}';
      }
      msg.content = content;
      event.onRecvRoomTextMsg && event.onRecvRoomTextMsg({
        roomID: roomInfo.roomID,
        userID: msg.fromAccountNick,
        userName: msg.userName,
        userAvatar: msg.userAvatar,
        message: msg.content,
        time: msg.time
      });
    } else if (contentObj.cmd == 'CustomCmdMsg') {
      msg.userName = contentObj.data.nickName;
      msg.userAvatar = contentObj.data.headPic;
      msg.cmd = contentObj.data.cmd;
      var content = '';
      for (var i = 1; i < newContent.length; i++) {
        if (i == newContent.length - 1)
          content += newContent[ i ];
        else content += newContent[ i ] + '}}';
      }
      msg.content = content;
      event.onRecvRoomCustomMsg && event.onRecvRoomCustomMsg({
        roomID: roomInfo.roomID,
        userID: msg.fromAccountNick,
        userName: msg.userName,
        userAvatar: msg.userAvatar,
        cmd: msg.cmd,
        message: msg.content,
        time: msg.time
      });
    }
  }
};

function recvC2CMsg(msg) {
  console.log("收到C2C消息:", JSON.stringify(msg));
  var contentObj = JSON.parse(msg.content);
  if (contentObj) {
    if (contentObj.cmd == 'linkmic') {
      if (contentObj.data.type && contentObj.data.type == 'request') {
        event.onRecvJoinPusherRequest({
          userID: msg.fromAccountNick,
          userName: contentObj.data.userName,
          userAvatar: contentObj.data.userAvatar
        })
      } else if (contentObj.data.type && contentObj.data.type == 'response') {
        if (contentObj.data.result == 'accept') {
          requestJoinCallback && requestJoinCallback({
            errCode: 0,
            errMsg: ''
          });
        } else if (contentObj.data.result == 'reject') {
          requestJoinCallback && requestJoinCallback({
            errCode: -999,
            errMsg: '主播拒绝了你的请求'
          });
        }
      } else if (contentObj.data.type && contentObj.data.type == 'kickout') {
        event.onKickOut && event.onKickOut({
          roomID: contentObj.data.roomID
        });
      }
    }
  }
}

function mergePushers() {
  if (!roomInfo.hasJoinPusher) {
    return;
  }
  getPushers({
    data: {
      roomID: roomInfo.roomID
    },
    success: function (ret) {
      ret = ret.data;
      /**
       * enterPushers：新进推流人员信息
       * leavePushers：退出推流人员信息
       * ishave：用于判断去重操作
       */
      var enterPushers = [], leavePushers = [], ishave = 0;
      console.log('去重操作');
      console.log('旧', JSON.stringify(roomInfo.pushers));
      console.log('新', JSON.stringify(ret.pushers));
      console.log('用户信息:', JSON.stringify(accountInfo));
      ret.pushers && ret.pushers.forEach(function (val1) {
        ishave = 0;
        roomInfo.pushers && roomInfo.pushers.forEach(function (val2) {
          if (val1.userID == val2.userID) {
            ishave = 1;
          }
        });
        if (!ishave && val1.userID != accountInfo.userID)
          enterPushers.push(val1);
        ishave = 0;
      });
      roomInfo.pushers && roomInfo.pushers.forEach(function (val1) {
        ishave = 0;
        ret.pushers && ret.pushers.forEach(function (val2) {
          if (val1.userID == val2.userID) {
            ishave = 1;
          }
        });
        if (!ishave)
          leavePushers.push(val1);
        ishave = 0;
      });
      // 重置roomInfo.pushers
      roomInfo.pushers = ret.pushers;
      // 通知有人进入房间
      if (enterPushers.length) {
        console.log('进房:', JSON.stringify(enterPushers));
        event.onPusherJoin && event.onPusherJoin({
          pushers: enterPushers
        });
        //混流
        mergeStream(1);
      }
      // 通知有人退出房间
      if (leavePushers.length) {
        console.log('退房:', JSON.stringify(leavePushers));
        event.onPusherQuit && event.onPusherQuit({
          pushers: leavePushers
        });
        //混流
        mergeStream(1);
      }
    },
    fail: function (ret) {
      // event.onRoomClose && event.onRoomClose({
      // 	errCode: ret.errCode,
      // 	errMsg: ret.errMsg
      // });
    }
  });
};

function getPushers(object) {
  var data = {};
  if (object.data && object.data.roomID) {
    data.roomID = object.data.roomID;
  } else if (roomInfo.roomID) {
    data.roomID = roomInfo.roomID;
  } else {
    object.fail && object.fail({
      errCode: -999,
      errMsg: '无roomID'
    })
    return;
  }
  //获取房间信息
  request({
    url: 'get_pushers',
    data: data,
    success: function (ret) {
      if (ret.data.code) {
        console.log('请求CGI:get_pushers失败', ret);
        object.fail && object.fail({
          errCode: ret.data.code,
          errMsg: '请求CGI:get_pushers失败:' + ret.data.message + +'[' + ret.data.code + ']'
        });
        return;
      }
      console.log("房间信息：", JSON.stringify(ret));
      object.success && object.success(ret);
    },
    fail: object.fail
  });
}

/**
 * [sendRoomTextMsg 发送文本消息]
 * @param {options}
 *   data: {
 *   	msg: 文本消息
 *   }
 */
function sendRoomTextMsg(options) {
  if (!options || !options.data.msg || !options.data.msg.replace(/^\s*|\s*$/g, '')) {
    console.log('sendRoomTextMsg参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'sendRoomTextMsg参数错误'
    });
    return;
  }
  webimhandler.sendCustomMsg({
    data: '{"cmd":"CustomTextMsg","data":{"nickName":"' + accountInfo.userName + '","headPic":"' + accountInfo.userAvatar + '"}}',
    text: options.data.msg
  }, function () {
    options.success && options.success();
  });
}

/**
 * [pusherHeartBeat 推流者心跳]
 * @param {options}
 */
function pusherHeartBeat(options) {
  if (options) {
    setTimeout(function () {
      proto_pusherHeartBeat();
    }, 3000);
  }
  if (heart) {
    setTimeout(function () {
      proto_pusherHeartBeat();
      pusherHeartBeat();
    }, 7000);
  }
}

function proto_pusherHeartBeat() {
  console.log('心跳请求');
  request({
    url: 'pusher_heartbeat',
    data: {
      roomID: roomInfo.roomID,
      userID: accountInfo.userID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('心跳失败：', ret);
        return;
      }
      console.log('心跳成功', ret);
    },
    fail: function (ret) {
      console.log('心跳失败：', ret);
    }
  });
}

/**
 * [stopPusherHeartBeat 停止推流者心跳]
 * @param {options}
 */
function stopPusherHeartBeat() {
  heart = false;
}

/**
 * [getRoomList 获取房间列表]
 * @param {options}
 *   data: {
 *   	index: 获取的房间开始索引，从0开始计算
 *   	cnt: 获取的房间个数
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   rooms: 房间列表信息
 */
function getRoomList(options) {
  if (!options) {
    console.log('getRoomList参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'getRoomList参数错误'
    });
    return;
  }
  request({
    url: 'get_room_list',
    data: {
      index: options.data.index || 0,
      cnt: options.data.cnt || 20
    },
    success: function (ret) {
      if (ret.data.code) {
        console.error('获取房间列表失败: ', ret);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log("房间列表信息:", ret);
      options.success && options.success({
        rooms: ret.data.rooms
      });
    },
    fail: function (ret) {
      console.log('获取房间列表失败: ', ret);
      if (ret.errMsg == 'request:fail timeout') {
        var errCode = -1;
        var errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode || -1,
        errMsg: errMsg || '获取房间列表失败'
      });
    }
  });
}

/**
 * [getPushURL 获取推流地址]
 * @param {options}
 *   success: 成功回调
 *   fail: 失败回调
 *
 * @return success
 *   pushURL: 推流地址
 */
function getPushURL(options) {
  if (!options) {
    console.log('getPushURL参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'getPushURL参数错误'
    });
    return;
  }
  request({
    url: 'get_push_url',
    data: {
      userID: accountInfo.userID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('获取推流地址失败: ', ret);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log('获取推流地址成功：', ret.data.pushURL);
      options.success && options.success({
        pushURL: ret.data.pushURL
      });
    },
    fail: function (ret) {
      if (ret.errMsg == 'request:fail timeout') {
        var errCode = -1;
        var errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode || -1,
        errMsg: errMsg || '获取推流地址失败'
      });
    }
  });
};

/**
 * [setListener 设置监听事件]
 * @param {options}
 *   onRoomClose: 群解散通知
 *   onRecvRoomTextMsg: 消息通知
 */
function setListener(options) {
  if (!options) {
    console.log('setListener参数错误', options);
    return;
  }
  event.onGetPusherList = options.onGetPusherList || function () {
  };
  event.onPusherJoin = options.onPusherJoin || function () {
  };
  event.onPusherQuit = options.onPusherQuit || function () {
  };
  event.onRoomClose = options.onRoomClose || function () {
  };
  event.onRecvRoomTextMsg = options.onRecvRoomTextMsg || function () {
  };
  event.onRecvJoinPusherRequest = options.onRecvJoinPusherRequest || function () {
  };
  event.onKickOut = options.onKickOut || function () {
  };
  event.onRecvRoomCustomMsg = options.onRecvRoomCustomMsg || function () {
  };
  event.onSketchpadData = options.onSketchpadData || function () {
  };
  event.onPushersChange = options.onPushersChange || function () {
  };
}

/**
 * [createRoom 创建房间]
 * @param {options}
 *   data: {
 *   	roomInfo: 房间名称
 *    	pushURL: 推流地址
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function createRoom(options) {
  roomInfo.isCreator = true;
  roomInfo.isDestory = false;
  roomInfo.isJoinGroup = false;
  if (!options || !options.data.roomInfo || !options.data.pushURL) {
    console.log('createRoom参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'createRoom参数错误'
    });
    return;
  }
  roomInfo.roomInfo = options.data.roomInfo;
  proto_createRoom(options);
}

function proto_createRoom(options) {
  request({
    url: 'create_room',
    data: {
      userID: accountInfo.userID,
      roomInfo: roomInfo.roomInfo
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('创建房间失败:', ret);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log('--->创建房间成功:', ret);
      roomInfo.roomID = ret.data.roomID;
      roomInfo.roomCreator = accountInfo.userID;
      if (roomInfo.isDestory) {
        roomInfo.isDestory = false;
        destoryRoom({});
        return;
      }
      options.data.roomID = ret.data.roomID;
      // 进入IM群
      webimhandler.applyJoinBigGroup(roomInfo.roomID, afterJoinBigGroup, {
        success: function () {
          joinPusher(options);
        },
        fail: options.fail
      });
    },
    fail: function (ret) {
      console.log('创建后台房间失败:', ret);
      if (ret.errMsg == 'request:fail timeout') {
        var errCode = -1;
        var errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode || -3,
        errMsg: errMsg || '创建房间失败'
      });
    }
  });
}

/**
 * [joinPusher 加入推流]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   	pushURL: 推流地址
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function joinPusher(options) {
  if (!options || !options.data.roomID || !options.data.pushURL) {
    console.log('joinPusher参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'joinPusher参数错误'
    });
    return;
  }
  roomInfo.roomID = options.data.roomID;
  roomInfo.isDestory = false;
  proto_joinPusher(options);
}

function proto_joinPusher(options) {
  request({
    url: 'add_pusher',
    data: {
      roomID: roomInfo.roomID,
      userID: accountInfo.userID,
      userName: accountInfo.userName,
      userAvatar: accountInfo.userAvatar,
      pushURL: options.data.pushURL
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('进入房间失败:', ret);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      roomInfo.hasJoinPusher = true;
      mergePushers();
      console.log('加入推流成功');
      // 开始心跳
      heart = true;
      pusherHeartBeat(1);
      options.success && options.success({ roomID: roomInfo.roomID });
    },
    fail: function (ret) {
      console.log('进入房间失败:', ret);
      if (ret.errMsg == 'request:fail timeout') {
        var errCode = -1;
        var errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode || -4,
        errMsg: errMsg || '进入房间失败'
      });
    }
  });
}

/**
 * [enterRoom 进入房间]
 * @param {options}
 *   data: {
 *   	roomID: 房间ID
 *   }
 *   success: 成功回调
 *   fail: 失败回调
 */
function enterRoom(options) {
  roomInfo.isCreator = false;
  roomInfo.isJoinGroup = false;
  if (!options || !options.data.roomID) {
    console.log('enterRoom参数错误', options);
    options.fail && options.fail({
      errCode: -9,
      errMsg: 'enterRoom参数错误'
    });
    return;
  }
  roomInfo.roomID = options.data.roomID;
  proto_enterRoom({
    success: function (ret) {
      options.success && options.success(ret);
      var userInfo = {
        userName: accountInfo.userName,
        userAvatar: accountInfo.userAvatar
      }
      addAudience({
        data: {
          roomID: options.data.roomID,
          userID: accountInfo.userID,
          userInfo: JSON.stringify(userInfo)
        }
      })
    },
    fail: options.fail
  });
}

function proto_enterRoom(options) {
  //roomInfo.roomID = 'room_test'
  console.log('开始IM: ', roomInfo.roomID);
  webimhandler.applyJoinBigGroup(roomInfo.roomID, afterJoinBigGroup, {
    success: function (ret) {
      getPushers({
        data: {
          roomID: roomInfo.roomID
        },
        success: function (ret) {
          roomInfo.roomID = ret.data.roomID;
          roomInfo.roomInfo = ret.data.roomInfo;
          roomInfo.roomCreator = ret.data.roomCreator;
          roomInfo.mixedPlayURL = ret.data.mixedPlayURL;
          options.success && options.success({
            roomID: roomInfo.roomID,
            roomCreator: roomInfo.roomCreator,
            mixedPlayURL: roomInfo.mixedPlayURL,
            pushers: ret.data.pushers
          });
        },
        fail: function (ret) {
          options.fail && options.fail({
            errCode: ret.errCode,
            errMsg: ret.errMsg || '拉取主播信息失败'
          });
        }
      });
    },
    fail: options.fail
  });
}

/**
 * [clearRequest 中断请求]
 * @param {options}
 */
function clearRequest() {
  for (var i = 0; i < requestSeq; i++) {
    requestTask[ i ].abort();
  }
  requestTask = [];
  requestSeq = 0;
}

/**
 * [exitRoom 退出房间]
 * @param {options}
 */
function exitRoom(options) {
  if (roomInfo.isCreator) {
    destoryRoom(options);
  } else {
    leaveRoom(options);
  }
  roomInfo.isDestory = true;
  roomInfo.roomID = '';
  roomInfo.pushers = [];
  roomInfo.mixedPlayURL = "";
  roomInfo.roomInfo = "";
  accountInfo.pushURL = "";
  accountInfo.isCreator = false;
}

/**
 * [leaveRoom 退出房间]
 */
function leaveRoom(options) {
  // 停止心跳
  stopPusherHeartBeat();
  // clearRequest();
  roomInfo.isJoinGroup && webimhandler.quitBigGroup();
  request({
    url: 'delete_pusher',
    data: {
      roomID: roomInfo.roomID,
      userID: accountInfo.userID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('退出推流失败:', ret);
        console.error('退房信息: roomID:' + roomInfo.roomID + ", userID:" + accountInfo.userID);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log('退出推流成功');
      roomInfo.roomID = '';
      options.success && options.success({});
    },
    fail: function (ret) {
      console.log('退出推流失败:', ret);
      var errCode = ret.errCode || -1;
      var errMsg = ret.errMsg || '退出房间失败'
      if (ret.errMsg == 'request:fail timeout') {
        errCode = -1;
        errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode,
        errMsg: errMsg
      });
    }
  });
  delAudience({
    data: {
      userID: accountInfo.userID,
      roomID: roomInfo.roomID
    }
  })
}

/**
 * [destoryRoom 销毁房间]
 */
function destoryRoom(options) {
  // 停止心跳
  stopPusherHeartBeat();
  // clearRequest();
  roomInfo.isJoinGroup && webimhandler.quitBigGroup();
  if (roomInfo.isDestory) return;
  request({
    url: 'destroy_room',
    data: {
      roomID: roomInfo.roomID,
      userID: accountInfo.userID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('关闭房间失败:', ret);
        console.error('关闭房间失败: roomID:' + roomInfo.roomID + ", userID:" + accountInfo.userID);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log('关闭房间成功');
      roomInfo.roomID = '';
      options.success && options.success({});
    },
    fail: function (ret) {
      console.log('关闭房间失败:', ret);
      var errCode = ret.errCode || -1;
      var errMsg = ret.errMsg || '关闭房间失败'
      if (ret.errMsg == 'request:fail timeout') {
        errCode = -1;
        errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode,
        errMsg: errMsg
      });
    }
  });
}

function quitPusher(options) {
  stopPusherHeartBeat();
  request({
    url: 'delete_pusher',
    data: {
      roomID: roomInfo.roomID,
      userID: accountInfo.userID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('退出推流失败:', ret);
        options.fail && options.fail({
          errCode: ret.data.code,
          errMsg: ret.data.message + '[' + ret.data.code + ']'
        });
        return;
      }
      console.log('退出推流成功');
      roomInfo.roomID = '';
      roomInfo.pushers = [];
      options.success && options.success({});
    },
    fail: function (ret) {
      console.log('退出推流失败:', ret);
      if (ret.errMsg == 'request:fail timeout') {
        var errCode = -1;
        var errMsg = '网络请求超时，请检查网络状态';
      }
      options.fail && options.fail({
        errCode: errCode || -1,
        errMsg: errMsg || '退出房间失败'
      });
    }
  });
  roomInfo.hasJoinPusher = false;
}

function requestJoinPusher(object) {
  var body = {
    cmd: 'linkmic',
    data: {
      type: 'request',
      roomID: roomInfo.roomID,
      userID: accountInfo.userID,
      userName: accountInfo.userName,
      userAvatar: accountInfo.userAvatar
    }
  }
  requestJoinCallback = function (ret) {
    if (gTimeoutID) {
      clearTimeout(gTimeoutID);
      gTimeoutID = null;
    }
    if (ret.errCode) {
      object.fail && object.fail(ret);
    } else {
      object.success && object.success(ret);
    }
  }
  var isTimeout = false;
  gTimeoutID = setTimeout(function () {
    gTimeoutID = null;
    console.error('申请连麦超时:', JSON.stringify(object.data));
    isTimeout = true;
    requestJoinCallback && requestJoinCallback({
      errCode: -999,
      errMsg: '申请加入连麦超时'
    });
  }, (object.data && object.data.timeout) ? object.data.timeout : 30000);
  var msg = {
    data: JSON.stringify(body)
  }
  webimhandler.sendC2CCustomMsg(roomInfo.roomCreator, msg, function (ret) {
    if (isTimeout) {
      return;
    }
    if (ret && ret.errCode) {
      console.log('请求连麦失败:', JSON.stringify(ret));
      requestJoinCallback && requestJoinCallback(ret);
      return;
    }
  });
}

function acceptJoinPusher(object) {
  var body = {
    cmd: 'linkmic',
    data: {
      type: 'response',
      result: 'accept',
      message: '',
      roomID: roomInfo.roomID
    }
  }
  var msg = {
    data: JSON.stringify(body)
  }
  webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {
  });
}

function rejectJoinPusher(object) {
  var body = {
    cmd: 'linkmic',
    data: {
      type: 'response',
      result: 'reject',
      message: object.data.reason || '',
      roomID: roomInfo.roomID
    }
  }
  var msg = {
    data: JSON.stringify(body)
  }
  webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {
  });
}

function kickoutSubPusher(object) {
  var body = {
    cmd: 'linkmic',
    data: {
      type: 'kickout',
      roomID: roomInfo.roomID
    }
  }
  var msg = {
    data: JSON.stringify(body)
  }
  webimhandler.sendC2CCustomMsg(object.data.userID, msg, function (ret) {
    if (ret && ret.errCode == 0) {
      object.success && object.success(ret);
    } else {
      object.fail && object.fail(ret);
    }
  });
}

function getAccountInfo() {
  return accountInfo;
}

/**
 *
 * @param {Int} retryCount
 */
function mergeStream(retryCount) {
  if (accountInfo.userID != roomInfo.roomCreator) {
    //大主播才能混流
    return;
  }
  var mergeStreams = [];
  if (roomInfo.pushers && roomInfo.pushers.length > 0) {
    roomInfo.pushers.forEach(function (val) {
      if (val.userID != roomInfo.roomCreator) {
        //获取流id
        var streamID = getStreamIDByStreamUrl(val.accelerateURL);
        if (streamID) {
          mergeStreams.push({
            userID: val.userID,
            streamID: streamID,
            width: val.width,
            height: val.height
          });
        }
      } else {
        bigAnchorStreamID = getStreamIDByStreamUrl(val.accelerateURL);
      }
    });
  }
  console.log("混流信息:", JSON.stringify(mergeStreams));
  sendStreamMergeRequest(retryCount, mergeStreams);
}

function getStreamIDByStreamUrl(streamUrl) {
  if (!streamUrl) {
    return null;
  }
  //推流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345?txSecret=aaa&txTime=bbb
  //拉流地址格式: rtmp://8888.livepush.myqcloud.com/path/8888_test_12345
  //             http://8888.livepush.myqcloud.com/path/8888_test_12345.flv
  //             http://8888.livepush.myqcloud.com/path/8888_test_12345.m3u8
  var subStr = streamUrl;
  var index = subStr.indexOf('?');
  if (index >= 0) {
    subStr = subStr.substring(0, index);
  }
  if (!subStr) {
    return null;
  }
  index = subStr.lastIndexOf('/');
  if (index >= 0) {
    subStr = subStr.substring(index + 1);
  }
  if (!subStr) {
    return null;
  }
  index = subStr.indexOf('.');
  if (index >= 0) {
    subStr = subStr.substring(0, index);
  }
  if (!subStr) {
    return null;
  }
  return subStr;
}

function sendStreamMergeRequest(retryCount, mergeStreams) {
  if (retryCount < 0) {
    return;
  }
  var mergeInfo = createMergeInfo(mergeStreams);
  console.log('混流信息:', JSON.stringify(mergeInfo));
  doMergeRequest(mergeInfo, function (ret) {
    if (ret) {
      console.log('混流成功');
    } else {
      console.log('混流失败');
      setTimeout(() => {
        retryCount--;
        sendStreamMergeRequest(retryCount, mergeStreams);
      }, 2000);
    }
  });
}

function doMergeRequest(mergeInfo, callback) {
  request({
    url: 'merge_stream',
    data: {
      userID: accountInfo.userID,
      roomID: roomInfo.roomID,
      mergeParams: JSON.stringify(mergeInfo)
    },
    success: function (ret) {
      if (ret.data.code || ret.data.result.code) {
        console.error('混流失败:', JSON.stringify(ret));
        callback(false);
        return;
      }
      callback(true);
    },
    fail: function (ret) {
      callback(false);
    }
  })
}

function createMergeInfo(mergeStreams) {
  console.log("混流原始信息:", JSON.stringify(mergeStreams));
  var smallAnchorWidth = 160;
  var smallAnchorHeight = 240;
  var offsetHeight = 90;
  if (bigAnchorWidth < 540 || bigAnchorHeight < 960) {
    smallAnchorWidth = 120;
    smallAnchorHeight = 180;
    offsetHeight = 60;
  }
  //组装混流JSON结构体
  var streamInfoArray = [];
  if (mergeStreams && mergeStreams.length > 0) {

    //大主播
    var bigAnchorInfo = {
      input_stream_id: bigAnchorStreamID || '',
      layout_params: {
        image_layer: 1
      }
    }
    streamInfoArray.push(bigAnchorInfo);
    //小主播
    var subLocationX = bigAnchorWidth - smallAnchorWidth;
    var subLocationY = bigAnchorHeight - smallAnchorHeight - offsetHeight;
    if (mergeStreams && mergeStreams.length > 0) {
      var layerIndex = 0
      mergeStreams.forEach(function (val) {
        //组装JSON
        var smallAchorInfo = {
          input_stream_id: val.streamID,
          layout_params: {
            image_layer: layerIndex + 2,
            image_width: smallAnchorWidth,
            image_height: smallAnchorHeight,
            location_x: subLocationX,
            location_y: subLocationY - layerIndex * smallAnchorHeight
          }
        }
        streamInfoArray.push(smallAchorInfo);
        layerIndex++;
      });
    }
  } else {
    var bigAnchorInfo = {
      input_stream_id: bigAnchorStreamID || '',
      layout_params: {
        image_layer: 1
      }
    }
    streamInfoArray.push(bigAnchorInfo);
  }
  var para = {
    app_id: accountInfo.sdkAppID.toString(),
    interface: 'mix_streamv2.start_mix_stream_advanced',
    mix_stream_session_id: bigAnchorStreamID,
    output_stream_id: bigAnchorStreamID,
    input_stream_list: streamInfoArray
  }
  var interfaceObj = {
    interfaceName: 'Mix_StreamV2',
    para: para
  }
  var reqParam = {
    timestamp: Math.round((Date.now() / 1000)),
    eventId: Math.round((Date.now() / 1000)),
    interface: interfaceObj
  }
  return reqParam;
}

function setVideoRatio(ratio) {
  if (ratio == 1) {
    //9:16
    bigAnchorWidth = 360;
    bigAnchorHeight = 640;
  } else {
    //3:4
    bigAnchorWidth = 480;
    bigAnchorHeight = 640;
  }
}

function sendC2CCustomMsg(object) {
  var body = {
    cmd: object.cmd,
    data: {
      userID: accountInfo.userID,
      userName: accountInfo.userName,
      userAvatar: accountInfo.userAvatar,
      msg: object.msg || ''
    }
  }
  var msg = {
    data: JSON.stringify(body)
  }
  webimhandler.sendC2CCustomMsg(object.toUserID ? object.toUserID : roomInfo.roomCreator, msg, function (ret) {
    if (ret && ret.errCode) {
      console.log('请求连麦失败:', JSON.stringify(ret));
      object.fail && object.fail(ret);
      return;
    }
    object.success && object.success({});
  });
}

//观众进房时，向后台发送进房通知
function addAudience(object) {
  request({
    url: 'add_audience',
    data: {
      userID: accountInfo.userID,
      roomID: object.data.roomID,
      userInfo: object.data.userInfo
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('增加观众请求失败', ret);
        object.fail && object.fail({
          errCode: ret.data.code,
          errMsg: '增加观众请求失败:' + ret.data.message + +'[' + ret.data.code + ']'
        });
        return;
      }
      object.success && object.success(ret);
    },
    fail: object.fail
  });
}

//观众退房时，向后台发送退房通知
function delAudience(object) {
  request({
    url: 'delete_audience',
    data: {
      userID: object.data.userID,
      roomID: object.data.roomID
    },
    success: function (ret) {
      if (ret.data.code) {
        console.log('减少观众请求失败', ret);
        object.fail && object.fail({
          errCode: ret.data.code,
          errMsg: '减少观众请求失败:' + ret.data.message + +'[' + ret.data.code + ']'
        });
        return;
      }
      object.success && object.success(ret);
    },
    fail: object.fail
  });
}

/**
 * 对外暴露函数
 * @type {Object}
 */
export default {
  login: login,							// 初始化
  logout: logout,						// 结束初始化
  getRoomList: getRoomList,			// 拉取房间列表
  getPushURL: getPushURL,				// 拉取推流地址
  createRoom: createRoom,				// 创建房间
  enterRoom: enterRoom,				// 加入房间
  exitRoom: exitRoom,					// 退出房间
  sendRoomTextMsg: sendRoomTextMsg,	// 发送文本消息
  setListener: setListener,			// 设置监听事件
  joinPusher: joinPusher,
  quitPusher: quitPusher,
  requestJoinPusher: requestJoinPusher,
  acceptJoinPusher: acceptJoinPusher,
  rejectJoinPusher: rejectJoinPusher,
  kickoutSubPusher: kickoutSubPusher,
  getAccountInfo: getAccountInfo,
  setVideoRatio: setVideoRatio,
  sendC2CCustomMsg: sendC2CCustomMsg,
  getPushers: getPushers
  // addRemoteView: addRemoteView,
  // deleteRemoteView: deleteRemoteView
}
